/**
 * 
 */
package t4j.concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static t4j.net.mindview.util.Print.*;

class DelayedTask implements Runnable, Delayed {

	private static int counter = 0;
	private final int id = counter++;
	private final int delta;
	private final long trigger;
	
	//静态的，每生成一个任务都放到List里面
	protected static List<DelayedTask> sequence = new ArrayList<DelayedTask>();

	public DelayedTask(int delayInMilliseconds) {
		delta = delayInMilliseconds;
		
		//设置触发时间 = 当前 + 延迟
		trigger = System.nanoTime() + TimeUnit.NANOSECONDS.convert(delta, TimeUnit.MILLISECONDS);//将毫秒转换为纳秒

		sequence.add(this);
	}

	//生成每个任务之间的延迟时间比较，用来生成延迟队列
	@Override
	public int compareTo(Delayed arg) {
	
		DelayedTask that = (DelayedTask) arg;
		if (trigger < that.trigger)
			return -1;
		if (trigger > that.trigger)
			return 1;

		return 0;
	}

	//可以用来告知延迟到期有多长时间，或者延迟在多长时间之前已经到期
	//如果元素的getDelay()方法返回0或者小于0的时候才能将其出列
	@Override
	public long getDelay(TimeUnit unit) {

		return unit.convert(trigger - System.nanoTime(), TimeUnit.NANOSECONDS);//剩余延迟时间=触发时间-当前时间
	}

	@Override
	public void run() {
		printnb(this + " ");
	}

	public String summary() {
		return "(" + id + ":" + delta + ")";
	}

	public String toString() {
		return String.format("[%1$-4d]", delta) + " Task " + id;
	}

	//用来循环list，然后停止线程
	public static class EndSentinel extends DelayedTask {
		private ExecutorService exec;

		public EndSentinel(int delay, ExecutorService e) {

			super(delay);
			exec = e;
		}

		public void run() {

			for (DelayedTask pt : sequence) { 
				printnb(pt.summary() + " ");
			}

			System.out.println();

			System.out.println(this + " Calling shutdownNow()");

			exec.shutdownNow();
		}
	}
}

class DelayedTaskConsumer implements Runnable {
	private DelayQueue<DelayedTask> q;

	public DelayedTaskConsumer(DelayQueue<DelayedTask> q) {
		this.q = q;
	}

	@Override
	public void run() {
		try {
			while (!Thread.interrupted())
				q.take().run();// Run task whth the current thread 获取并移除此队列的头部，在可从此队列获得到期延迟的元素之前一直等待（如有必要）。
		} catch (InterruptedException e) {

			e.printStackTrace();
		}

		System.out.println("Finished DelayedTaskConsumer");

	}
}

public class DelayQueueDemo {
	public static void main(String[] args) {
		Random rand = new Random(47);
		
		ExecutorService exec = Executors.newCachedThreadPool();
		
		DelayQueue<DelayedTask> queue = new DelayQueue<DelayedTask>();
		
		for(int i = 0 ; i < 20 ; i++)
			queue.put(new DelayedTask(rand.nextInt(5000)));//将指定元素插入此延迟队列。
		
		queue.add(new DelayedTask.EndSentinel(100000, exec));//这个放在数组最后，用来停止线程
		
		exec.execute(new DelayedTaskConsumer(queue));
	}
}
